﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="XmlDocReflector.cs" company="xmldoc-reflector team">
//
// xmldoc-reflector, a library to access the XML code documentation of .NET assemblies
// Copyright (C) 2012 xmldoc-reflector team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/. 
// </copyright>
// <author>
//   <name>Roland Reinl</name>
//   <mail>reinlroland@googlemail.com</mail>
// </author>
// <history>
//   <historyitem date="2012-10-27" change="Created file"/>
// </history>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace XmlDocReflectorLib
{
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Reflection;
  using System.Xml;

  /// <summary>
  /// This class provides XML documentation elements.
  /// </summary>
  public static class XmlDocReflector
  {
    /// <summary>
    /// The already loaded xml documentation documents.
    /// </summary>
    private static readonly Dictionary<string, XmlDocument> LoadedDocuments = new Dictionary<string, XmlDocument>();

    /// <summary>
    /// Gets the XML doc comment of the specified type.
    /// </summary>
    /// <param name="memberInfo">The member info.</param>
    /// <returns>A list containing all selected elements.</returns>
    /// <exception cref="System.ArgumentOutOfRangeException">If the member type is not supported.</exception>
#if DOTNET20
    public static XmlDocNode GetXmlDoc(MemberInfo memberInfo)
#else
    public static XmlDocNode GetXmlDoc(this MemberInfo memberInfo)
#endif
    {
      string typeSpecifier;
      Type memberType = null;
      switch (memberInfo.MemberType)
      {
        case MemberTypes.TypeInfo:
          memberType = memberInfo as Type;
          typeSpecifier = "T:" + memberType.FullName;
          break;
        case MemberTypes.Property:
          memberType = memberInfo.DeclaringType;
          typeSpecifier = "P:" + memberInfo.DeclaringType.FullName + "." + memberInfo.Name;
          break;
        case MemberTypes.NestedType:
          memberType = memberInfo.DeclaringType;
          typeSpecifier = "T:" + memberInfo.DeclaringType.FullName + "." + memberInfo.Name;
          break;
        default:
          throw new ArgumentOutOfRangeException(string.Format("The type {0} is not supported", memberInfo.MemberType));
      }

      string xmlDocPath = Path.ChangeExtension(memberType.Assembly.Location, "xml");

      XmlDocument xmlDoc;
      if (LoadedDocuments.ContainsKey(xmlDocPath) == true)
      {
        xmlDoc = LoadedDocuments[xmlDocPath];
      }
      else
      {
        xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlDocPath);
        LoadedDocuments.Add(xmlDocPath, xmlDoc);
      }

      XmlNode node = xmlDoc.SelectSingleNode("/doc/members/member[@name='" + typeSpecifier + "']");
      if (node == null)
      {
        return null;
      }
      else
      {
        return new XmlDocNode(node);
      }
    }
  }
}
